#include "Indice.h"
#include "../../Util/Configuracion.h"
#include "../../Util/Util.h"

Indice::Indice(std::string& path):Operacion(path), iterAchivos(path){
	this->codigosMD5_por_IdDoc = new Lista<CodigoMD5_por_IdDoc>();
	this->calcularExistencia_delIndice();
	this->codigosMD5_por_IdDoc_modificados = new Lista<CodigoMD5_por_IdDoc>();
}

void Indice::calcularExistencia_delIndice(){
	FILE* fd = fopen(FILENAME_INDICE,"r");
	if (fd == NULL)
		this->existencia_indice = false;
	else
		this->existencia_indice = true;
}

bool Indice::getExistenciaIndice(){
	return this->existencia_indice;
}

void Indice::agregarCodigoMD5_por_IdDoc(tCodigoMD5 codigoMD5, tIdDoc idDoc){
	CodigoMD5_por_IdDoc codigoMD5_por_IdDoc(codigoMD5, idDoc);
	this->codigosMD5_por_IdDoc->agregar(codigoMD5_por_IdDoc);
}

void Indice::agregarCodigoMD5_por_IdDoc_modificados(tCodigoMD5 codigoMD5, tIdDoc idDoc){
	CodigoMD5_por_IdDoc codigoMD5_por_IdDoc(codigoMD5, idDoc);
	this->codigosMD5_por_IdDoc->agregar(codigoMD5_por_IdDoc);
}

bool Indice::coleccionFueModificada(){
	bool coleccionModificada = false;
	/*
	 * todo el siguiente metodo comentado se tiene que implementar en Lista.h
	 * */
	//this->codigosMD5_por_IdDoc->leerDeDisco(FILENAME_CODIGOSMD5_POR_IdDOC);
	while (this->iterAchivos.tieneSiguiente()){
		std::string ruta(iterAchivos.siguiente());

		Message_Digest md5(ruta.c_str());
		tCodigoMD5 md5ArchivoActual = md5.obtener_resumen();
		tIdDoc idDocActual = this->generarIdDoc(ruta); //ver comentario de la firma de este metodo.
		if (this->existeIdDocEn_codigosMD5_por_IdDoc(idDocActual)){
			if (md5ArchivoActual != this->getMD5segunIdDoc(idDocActual)){
				coleccionModificada = true;
				this->agregarCodigoMD5_por_IdDoc_modificados(md5ArchivoActual, idDocActual);
				//todo implementar la actualizacion de el indice si el MD5 de el archivo fue modificado
			}
		}
	}
	return coleccionModificada;
}

bool Indice::existeIdDocEn_codigosMD5_por_IdDoc(tIdDoc idDoc){
	bool existeIdDoc = true;
	/*
	 * todo buscar y verificar que este IdDoc este en la lista 'codigosMD5_por_IdDoc'.
	 * Esta estructura podria no ser una lista para que la busqueda sea rapida.
	 *
	 * */
	return existeIdDoc;
}

tCodigoMD5 Indice::getMD5segunIdDoc(tIdDoc idDoc){
	tCodigoMD5 codigoMD5_devolver("nada");
	//todo implementar la devolucion de un codigo MD5 mediante un IdDoc.
	return codigoMD5_devolver;
}

/*Cuando hable de documentos me referire a los archivos.
 *
 *Cuando hable de coleccion me refire al conjunto de todos mis documentos
 * que seran indexados.
 * */
void Indice::inicio(){
	std::cout<<"!!!!!!!!! ACA EMPIEZA EL INDEXADOR!!!!!!"<<std::endl;
	char buffer[512];
    std::cout<<"El directorio actual es: "<<getcwd(buffer, -1)<<std::endl;

	if (this->getExistenciaIndice()){
		cout<<"el indice ya existe!, se procede a la actualizacion"<<endl;
		//trabajo con el indice ya creado
		if (this->coleccionFueModificada()){

		}

	}else{
		cout<<"se crea el indice desde cero!"<<endl;
		//creo el indice desde cero
		/*
		 * este bloque de codigo se ejecuta una vez en la vida a menos que
		 * borre a mano indice.dat.Pero este caso no es parte de el enunciado
		 * */
		while (this->iterAchivos.tieneSiguiente()){
			std::string ruta(iterAchivos.siguiente());
			std::cout<<ruta<<std::endl;

			Message_Digest md5(ruta.c_str());
			tCodigoMD5 md5ArchivoActual = md5.obtener_resumen();
			tIdDoc idDocActual = this->generarIdDoc(ruta); //ver comentario de la firma de este metodo.
			this->agregarCodigoMD5_por_IdDoc(md5ArchivoActual, idDocActual);

			Lista<std::string>* listaTerminos = new Lista<std::string>();
			if (listaTerminos){
				long int nroDocumento = this->extratorTerminos.extraer(ruta, listaTerminos);
				// TODO: el indexador recibe los terminos normalizados y el numero de documento
				if (nroDocumento) {
					/*no es necesario ir indexando el 'md5ArchivoActual' por que el mismo se
					 * mismo se va a persistir mediante la lista 'codigosMD5_por_IdDoc'de manera
					 * independiente para que sea rapido su recuperacion en el momento que se tenga
					 * que correr el indexador por segunda vez, y tambien asi comprobar cuales
					 * documentos se tiene que reindexar.
					*/
					this->indexador.indexar(listaTerminos, nroDocumento);
				}
			}
			delete listaTerminos;
		}
		/*
		 * todo el siguiente metodo comentado se tiene que implementar en Lista.h
		 * */
		//this->codigosMD5_por_IdDoc->escribirEnDisco(FILENAME_CODIGOSMD5_POR_IdDOC);

		this->indexador.finalizar();
    }
}

tIdDoc Indice::generarIdDoc(std::string filename){
	//codifico el filename de acuerdo a las posiciones de sus caracteres en la palabra
	size_t size = filename.size();
	//para acumular los pesos de cada letra de la palabra
	int codigoParcial = 0;
	for(size_t i=0 ; i < size ; i++){
		codigoParcial = codigoParcial + i*(int)filename[i];
	}
	return (tIdDoc)codigoParcial;
}





